<template>
  <div>
    <el-card style="height: 80px">
      <el-form ref="form" :inline="true" class="upper">
        <el-form-item label="用户名:">
          <el-input placeholder="请输入要搜索的用户名" v-model="keyword"></el-input>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" @click="searchUser" :disabled="keyword.trim() ? false : true">搜索</el-button>
          <el-button @click="resetSearchUser">重置</el-button>
        </el-form-item>
      </el-form>
      <!-- card body -->
    </el-card>

    <el-card style="margin: 10px 0px">
      <el-button type="primary" size="default" @click="addUser">添加</el-button>
      <el-button type="danger" size="default" @click="deleteSelectedUser"
        :disabled="multipleSelectedUserIdList.length > 0 ? false : true">批量删除</el-button>

      <el-table ref="multipleTableRef" border :data="userList" @selection-change="handleSelectionChange">
        <el-table-column type="selection" />
        <el-table-column label="#" type="index" align="center" />
        <el-table-column label="id" width="80px" align="center" prop="id" />
        <el-table-column label="用户名字" show-overflow-tooltip align="center" prop="username" />
        <el-table-column label="用户昵称" show-overflow-tooltip align="center" prop="name" />
        <el-table-column label="用户角色" show-overflow-tooltip align="center" prop="roleName" />
        <el-table-column label="创建时间" show-overflow-tooltip align="center" prop="createTime" />
        <el-table-column label="更新时间" show-overflow-tooltip align="center" prop="updateTime" />
        <el-table-column label="操作" align="center" width="260px">
          <template #="{ row }">
            <el-button type="primary" size="small" icon="User" @click="assignRoleAction(row)">
              分配角色
            </el-button>
            <el-button type="primary" size="small" icon="Edit" @click="updateUser(row)">
              编辑
            </el-button>
            <!-- 气泡确认框 -->
            <el-popconfirm :title="`你确认要删除用户${row.username}`" @confirm="deleteUser(row.id)">
              <template #reference>
                <el-button type="primary" size="small" ifcon="Delete">
                  删除
                </el-button>
              </template>
            </el-popconfirm>
          </template>
        </el-table-column>
      </el-table>

      <!-- 分页器 -->
      <el-pagination v-model:current-page="pageNo" v-model:page-size="pageSize" :page-sizes="[5, 7, 9]" :background="true"
        layout="prev, pager, next, jumper,->,sizes,total" :total="total" />

      <!-- 抽屉结构：添加新的用户信息和更新已有的用户信息 -->
      <el-drawer v-model="drawerUser">
        <template #header>
          <h4>{{ userParams.id ? '修改用户' : '新增用户' }}</h4>
        </template>
        <template #default>
          <div>
            <div style="margin: 10px 0px">
              <el-alert title="注意:正在修改的为本人账号, 这将会导致强制重新登录!" type="warning" :closable="false" show-icon v-show="isAlert" />
            </div>
            <!-- 表单以及表单校验 -->
            <el-form ref="formRef" :rules="rules" :model="userParams">
              <el-form-item label="用户名称" prop="username">
                <el-input placeholder="请填写用户名字" v-model="userParams.username"></el-input>
              </el-form-item>

              <el-form-item label="用户昵称" prop="name">
                <el-input placeholder="请填写用户昵称" v-model="userParams.name"></el-input>
              </el-form-item>

              <el-form-item label="用户密码" prop="password" v-show="!userParams.id">
                <el-input placeholder="请填写用户密码" type="password" show-password v-model="userParams.password"></el-input>
              </el-form-item>
            </el-form>
          </div>
        </template>
        <template #footer>
          <div style="flex: auto">
            <el-button @click="cancel">取消</el-button>
            <el-button type="primary" @click="save">确定</el-button>
          </div>
        </template>
      </el-drawer>

      <!-- 抽屉结构: 分配角色 -->
      <el-drawer v-model="drawerRole">
        <template #header>
          <h4>分配角色(职位)</h4>
        </template>
        <template #default>
          <el-form ref="form">
            <el-form-item label="用户姓名">
              <el-input v-model="userParams.username" :disabled="true"></el-input>
            </el-form-item>
            <el-form-item label="角色列表">
              <el-checkbox v-model="checkAll" :indeterminate="isIndeterminate" @change="handleCheckAllChange">
                全选
              </el-checkbox>
              <!-- 显示职位的复选框 -->
              <el-checkbox-group v-model="checkedRoles" @change="handleCheckedRoleChange">
                <!-- 注意这里的label的值为单个role的对象值，否则无法呈现用户已有的选中值 -->
                <el-checkbox v-for="(role, index) in allRolesList" :key="index" :label="role">
                  {{ role.roleName }}
                </el-checkbox>
              </el-checkbox-group>
            </el-form-item>
          </el-form>
        </template>
        <template #footer>
          <div style="flex: auto">
            <el-button @click="drawerRole = false">取消</el-button>
            <el-button type="primary" @click="saveAssignRole">确定</el-button>
          </div>
        </template>
      </el-drawer>
    </el-card>
  </div>
</template>
<script setup lang="ts">
import { ref, reactive, onMounted, watch } from 'vue'
// 引入接口
import {
  reqAllUser,
  reqAddOrUpdateUser,
  reqAllRole,
  reqAssignUserRole,
  reqDeleteUser,
  reqBatchDeleteUser,
} from '@/api/acl/user'
// 获取全部用户数据类型
import type { User, AllRoleResponseData, AllRole } from '@/api/acl/user/type'
import { ElMessage } from 'element-plus/lib/components/index.js'
import useUserStore from '@/store/modules/user'
import useLayoutSetingStore from '@/store/modules/setting'
// 引入获取时间的模块
let useStore = useUserStore()

// 保存当前页码
let pageNo = ref<number>(1)
// 每页保存几条数据
let pageSize = ref<number>(5)
// 保存返回的数据总数
let total = ref<number>(0)
// 保存当前页的所有用户的数据
let userList = ref<User[]>([])
// 控制是否显示修改和更新用户屉的显示与隐藏
let drawerUser = ref<boolean>(false)
// 收集用户信息
let userParams = reactive<User>({
  username: '',
  name: '',
  password: '',
})

// 获取el-form表单实例对象,后续进行表单验证
let formRef = ref()
// 控制是否要提示用户的信息,如果用户修改的是个人的信息修改提醒他
let isAlert = ref<boolean>(false)

// 控制是否给用户分配角色抽屉的显示与隐藏
let drawerRole = ref<boolean>(false)

// 复选框搜集数据：是否全选
let checkAll = ref<boolean>(false)
// 存储要修改用户已有的角色
let checkedRoles = ref<AllRole>([])
// 存储全部角色的数据
let allRolesList = ref<AllRole>([])
// 设置不确定状态，仅负责样式控制
let isIndeterminate = ref<boolean>(true)
// 存储用户要搜索的用户名的关键字
let keyword = ref<string>('')

// 准备一个数组存放一个要删除的用户id的
const multipleSelectedUserIdList = ref<number[]>([])

// 引入小仓库
let useSeting = useLayoutSetingStore()

// 组件加载完去获取全部用户的信息
onMounted(() => {
  getUser()
})

// 获取用户函数独立出来，便于后面复用 (这里参数pageNum是为了让用户可以动态执行渲染哪一页的数据)
const getUser = async (pageNum = pageNo.value) => {
  pageNo.value = pageNum
  // keyword为要搜索的用户名称，默认为空
  let result = await reqAllUser(pageNo.value, pageSize.value, keyword.value)
  if (result.code == 200) {
    userList.value = result.data.records
    total.value = result.data.total
  }
}

// 当前页发生变化时，需要再次发生请求用户信息，返回指定页的数据
watch(pageNo, () => {
  getUser()
})

// 当改变每页要显示的数据的个数时，要从第一页开始展示
watch(pageSize, () => {
  getUser(1)
})

// 添加用户按钮的回调
const addUser = () => {
  // 显示抽屉效果
  drawerUser.value = true
  // 清空之前的数据
  Object.assign(userParams, {
    id: '', // 注意id也要清空，否则用户修改完id有值了，再新增id还有值就不对了。
    username: '',
    name: '',
    password: '',
  })
  isAlert.value = false
  // 清理字段的表单验证信息,对于首次添加由于还没有验证信息，这里就没有clearValidate方法
  formRef.value?.clearValidate(['name', 'username', 'password'])
}

// 修改用户按钮的回调
const updateUser = (row: User) => {
  // 显示抽屉效果
  drawerUser.value = true
  // 把当前行的数据赋值给userParams,表示存储收集已有的用户信息在抽屉中展示出来
  Object.assign(userParams, row)
  // 清理字段的表单验证信息,对于首次添加，由于还没有form组件，没有验证信息，这里就没有clearValidate方法，因此要进行特殊处理
  formRef.value?.clearValidate(['name', 'username', 'password'])

  // 检查用户修改的是否为个人账号信息，来决定是否需要提醒
  if (useStore.username == userParams.username) {
    isAlert.value = true
  } else {
    isAlert.value = false
  }
}

// 取消按钮的回调
const cancel = () => {
  // 隐藏抽屉效果
  drawerUser.value = false
}

// 确定按钮的回调
const save = async () => {
  // 保存之前需要先对表单进行校验，所有的表单字段通过校验才能发送请求
  await formRef.value.validate()

  // 保存按钮: 添加新的用户|更新已有的用户账号信息
  const result: any = await reqAddOrUpdateUser(userParams)
  // 关闭抽屉
  drawerUser.value = false
  if (result.code == 200) {
    // 显示提示信息
    ElMessage({
      type: 'success',
      message: userParams.id ? '修改用户成功' : '新增用户成功',
    })
    // 重新获取用户的账号信息
    // 特殊情况: 如果修改的是个人信息那么就需要刷新页面，让用户重新登录
    if (isAlert.value) {
      window.location.reload()
    } else {
      // 如果用户修改的不是个人账号,如果是新增就回到第一页，如果是修改还应停留在当前页
      getUser(userParams.id ? pageNo.value : 1)
    }
  } else {
    ElMessage({
      type: 'error',
      message: userParams.id ? '修改用户失败' : '新增用户失败',
    })
  }
}

// 验证用户名
const validatorName = (_: any, value: any, callback: any) => {
  if (value.trim().length >= 6) {
    callback()
  } else {
    callback(new Error('用户名不能少了6个字符'))
  }
}

// 验证用户输入密码
const validatorPassword = (_: any, value: any, callback: any) => {
  if (value.trim().length >= 8) {
    callback()
  } else {
    callback(new Error('密码不能少了8个字符'))
  }
}

// 定义表单校验规则对象
const rules = {
  name: [
    // required: true, 文本框会出现一个五角星
    { required: true, trigger: 'blur', validator: validatorName },
  ],
  username: [
    {
      required: true,
      min: 7,
      max: 15,
      message: '昵称为7-15个字符',
      trigger: 'blur',
    },
  ],
  password: [{ required: true, trigger: 'blur', validator: validatorPassword }],
}

// 分配角色的回调
const assignRoleAction = async (row: User) => {
  // 存储已有的用户的信息
  Object.assign(userParams, row)

  // 获取角色信息
  let result: AllRoleResponseData = await reqAllRole(row.id as number)
  if (result.code == 200) {
    // 存储全部的角色
    allRolesList.value = result.data.allRolesList
    // 存储要修改用户已有的角色
    checkedRoles.value = result.data.assignRoles
    // 显示分配角色的抽屉
    drawerRole.value = true
  }
}

// 全选的复选框的change事件
const handleCheckAllChange = (val: boolean) => {
  // val：true（全选）|false（没有全选）
  // 如果全选，就把全部的值的赋值给选中的值列表，即全选就需要把底部复选框都勾上
  checkedRoles.value = val ? allRolesList.value : []
  // 为false，顶部复选框为不确定样式；为true，顶部复选框为确定样式
  isIndeterminate.value = false
}
// 底部复选框change事件（参数value为选中的每一个对象组成的列表）
const handleCheckedRoleChange = (value: string[]) => {
  // 选中值的列表长度
  const checkedCount = value.length
  // 是否全选即checkAll.value为true还是false，要根据后面的表达式判断，如果选中值的列表长度和全部值列表的长度相等，为true,否则为false
  checkAll.value = checkedCount === allRolesList.value.length
  //是否为不确定样式即isIndeterminate.value为true还是false，要根据后面的表达式来判断， 当选中值的数据量大于0且选中值列表的长度小于全部值的长度时，为true,否则为false
  isIndeterminate.value =
    checkedCount > 0 && checkedCount < allRolesList.value.length
}

// 保存分配的角色
const saveAssignRole = async () => {
  let result = await reqAssignUserRole({
    userId: userParams.id as number,
    roleIdList: checkedRoles.value.map((item) => item.id as number),
  })
  // 关闭抽屉
  drawerRole.value = false
  if ((result.code = 200)) {
    // 提示信息
    ElMessage({ type: 'success', message: '分配角色成功' })
    // 重新请求用户信息,留在当前页
    getUser()
  } else {
    // 提示信息
    ElMessage({ type: 'error', message: '分配角色失败' })
  }
}

// 删除单个用户
const deleteUser = async (userId: number) => {
  console.log('delete user')

  let result = await reqDeleteUser(userId)
  if ((result.code = 200)) {
    // 提示信息
    ElMessage({ type: 'success', message: '删除用户成功' })
    // 重新请求用户信息,如果当前页所有的用户数据数大于1，则留在当前页，否则返回上一页
    getUser(userList.value.length > 1 ? pageNo.value : pageNo.value - 1)
  } else {
    // 提示信息
    ElMessage({ type: 'error', message: '删除用户失败' })
  }
}


// table复选框选中的勾选的时候会触发的事件
const handleSelectionChange = (val: User[]) => {
  // val为每行数据的对象
  // 整理批量删除的用户id的列表
  multipleSelectedUserIdList.value = val.map((item) => (item.id as number))
}

// 删除多个用户
const deleteSelectedUser = async () => {
  let result = await reqBatchDeleteUser(multipleSelectedUserIdList.value)
  if ((result.code = 200)) {
    // 提示信息
    ElMessage({ type: 'success', message: '删除成功' })
    // 重新请求用户信息,如果当前页所有的用户数据数大于1，则留在当前页，否则返回上一页
    getUser(userList.value.length > 1 ? pageNo.value : pageNo.value - 1)
  } else {
    // 提示信息
    ElMessage({ type: 'error', message: '删除失败' })
  }
}

// 根据用户名搜索用户按钮回调
const searchUser = () => {
  getUser()
  // 清空keyword
  keyword.value = ''
}

// 重置搜索用户按钮的回调，组件的销毁和重建和顶部菜单的刷新功能是一样的,调一下原有的功能即可
const resetSearchUser = () => {
  useSeting.isRefresh = !useSeting.isRefresh
}

</script>
<script lang="ts">
export default {
  name: 'AclUser',
}
</script>

<style scope lang="scss">
.upper {
  display: flex; // 浮动
  justify-content: space-between; // 一左一右
  align-items: center;
}
</style>
